$EP
$MOD186
Name LCD

;; Serial routines for 8088 microcomputer system
;
; Filename:	Timer.ASM
;
; Author: 	Law Wen Yong
;
; This file contains proprietory information and cannot be copied 
; or distributed without prior permission from the author.
;---------------------------------------------------------------------------

;API:
;Remember to put 10,13 in front of the string when you declare string in the 
;data segment
public LCD_init ;initialise LCD
public write_char_to_LCD; parameter BL 
;public read_out_LCD_info ;return al ;debugging
public write_string_to_LCD ;parameter SI - address of string 
						;parameter ES - section address
						;size=16
						;parameter AL to indicate which line to display
						;1 to indicate 1st line
						;2 to indicate 2nd line
						;add 0 at the back to indicate end of the string
						
public output_LCD_status ;return al for status
public LCD_display_now ;display  LCD now




LCD_DATA_SEG SEGMENT

	LCD_status DB 0	;current status of the LCD
	cur_index DB 0 ;index of the cur_line

	cur_line DB 0
	lines_to_display DB 0 
	
	LCD_1st_line_buffer DB 16 dup(0) 
	LCD_2nd_line_buffer DB 16 dup(0) 


LCD_DATA_SEG ENDS



$include(LCD.inc)
$include(PPI.inc)


LCD_Routine SEGMENT
ASSUME CS:LCD_Routine

LCD_init PROC FAR  
	
	Push AX
	Push BX
	Push CX
	Push DX
	

	Mov AL,01H
	out portA, AL	;Enable LED
	
	Mov BL, Func_set
	call far ptr set_LCD_register_init
	
	Mov BL, Func_set
	call far ptr set_LCD_register_init
	
		
	Mov BL, Func_set
	call far ptr set_LCD_register_init
	
		
	Mov BL, Func_set
	call far ptr set_LCD_register_init

	
	MOV BL, LCD_display_off  ;Display off
	call far ptr set_LCD_register
	
	MOV BL, LCD_CL_Display ;clear display
	call far ptr set_LCD_register
	
	MOV BL, LCD_entry_mode_set; entry mode set
	call far ptr set_LCD_register
	
	MOV BL, LCD_display_on 
	call far ptr set_LCD_register
	
	MOV BL, LCD_return_home
	call far ptr set_LCD_register
	
  
	

	Pop DX
	Pop CX
	Pop BX
	Pop AX
	
	RET

LCD_init ENDP


Read_out_LCD_info proc far
	push AX

	mov AL, set_PortB_in
	out CWR, AL
	mov AL, LCD_RD_Register
	out PortA, AL
	
	nop
	nop
	nop
	
	in AL, portB
	Mov BL,AL
	
	nop
	nop
	nop
	
    mov AL, disable_LCD_signal
	out PortA, AL
	
	mov AL, set_PortB_out
	out CWR, AL
	
	pop AX


Read_out_LCD_info endp

Delay2ms proc far
	push bx
	mov	bx,008Fh	; Reset the countdown timer.
	Delay2msDecrement:
	dec	bx			; Decrement it by 1 each time.  
	cmp	bx,00h		
	jnz	Delay2msDecrement			; If the counter hasn't counted
						; down to 00h yet, keep going.
	pop bx
	ret
Delay2ms endp



set_LCD_register_init PROC FAR   ;set_register ;parameter BL
						
	
	push AX
	push DX
	
	
	Mov AL, LCD_WR_Register
	out PortA, AL
	
	Mov AL, BL
	out PortB, AL
	call far ptr Delay2ms
	call far ptr Delay2ms
	call far ptr Delay2ms
	;call far ptr Delay2ms
	mov AL, disable_LCD_signal
	out portA, AL
	out portB, AL
	call far ptr Delay2ms
	call far ptr Delay2ms
	call far ptr Delay2ms
	call far ptr Delay2ms
	call far ptr Delay2ms
	
	pop DX
	pop AX

	
	ret
set_LCD_register_init ENDP


set_LCD_register PROC FAR   ;set_register ;parameter BL
						
	
	push AX
	push DX
	
	LCD_reg_wait: ;check for busy flag if busy loop
	mov AL, disable_LCD_signal
	out PortA, AL
 	nop
	nop
	nop
	
	
	mov AL, set_PortB_in
	out CWR, AL
	mov AL, LCD_RD_Register
	out PortA, AL
	nop
	nop
	nop

	in AL, portB
	MOV AH,AL
	and AL, Read_BFlag
	Mov DL, Read_BFlag
	cmp DL, AL
	

	
	JE LCD_reg_wait
	
    mov AL, disable_LCD_signal
	out PortA, AL
	nop
	nop
	nop
		
	mov AL, set_PortB_out
	out CWR, AL
	
	Mov AL, LCD_WR_Register
	out PortA, AL

	
	Mov AL, BL
	out PortB, AL
	nop
	nop
	nop
	nop
	nop
	;call far ptr Delay2ms
	mov AL, disable_LCD_signal
	out portA, AL
	out portB, AL

	
	pop DX
	pop AX

	
	ret
set_LCD_register ENDP



write_char_to_LCD PROC FAR ;BL parameter

	push AX
	push DX
	

	LCD_reg_wait2: ;check for busy flag if busy loop
	mov AL, disable_LCD_signal
	out PortA, AL
 	nop
	nop
	nop
	
    
	mov AL, set_PortB_in
	out CWR, AL
	mov AL, LCD_RD_Register
	out PortA, AL
	nop
	nop
	nop

	in AL, portB
	MOV AH,AL
	and AL, Read_BFlag
	Mov DL, Read_BFlag
	cmp DL, AL
	

	
	JE LCD_reg_wait2
	
    mov AL, disable_LCD_signal
	out PortA, AL
	
	nop
	nop
	nop
		
	mov AL, set_PortB_out
	out CWR, AL
	
	Mov AL, LCD_WR_Char
	out PortA, AL

	Mov AL, BL
	out PortB, AL
	nop
	nop
	nop
	mov AL, disable_LCD_signal
	out portA, AL
	out portB, AL
	
	
	pop DX
	pop AX
	
	ret
write_char_to_LCD ENDP

output_LCD_status Proc far ;return AL
	push DS
	push BX
	
	MOV BX, LCD_DATA_SEG
	
	MOV DS, BX
	
	MOV AL, DS:LCD_status
	
	pop BX
	pop DS
	ret

output_LCD_status endp

write_string_to_LCD proc far ;parameter SI - address of string 
						;size 16 indicate the end of string
						;parameter AL to indicate which line to display
	push DS
	push BX
	push DI
	
	MOV BX, LCD_DATA_SEG
	MOV DS, BX
	;LCD check if line1:
	MOV AH, cur_line1
	cmp AL,AH
    JNE LCD_check_if_line2
	
	;call write to 1st line buffer function:
	
	;update line to display
	OR DS:lines_to_display, AL
	mov DI, offset LCD_1st_line_buffer 
	call far ptr LCD_write_to_buffer 
	
	
	jmp LCD_end_write_string
	
	
    LCD_check_if_line2:
	
	MOV AH, cur_line2
	cmp AL, AH
	JNE LCD_end_write_string
	;call write to 2nd line buffer function:
	
	;update line to display
	OR DS:lines_to_display, AL
	mov DI, offset LCD_2nd_line_buffer 
	call far ptr LCD_write_to_buffer 
	
	LCD_end_write_string:
	pop DI
	pop BX
	pop DS
	ret

write_string_to_LCD endp


LCD_write_to_buffer proc far  ;parameter SI - source to copy from.
							 ;parameter DI - destination to copy to
							 ;null character which 0 indicate the end of string
	push AX
	push CX
	
	MOV CX, LCD_buffer_size

	LCD_buffer_loop:
	mov AL, ES:[SI]
	mov [DI], AL
	inc SI
	inc DI
	
	loop LCD_buffer_loop
	
	pop CX
	pop AX
	
	ret
LCD_write_to_buffer endp

LCD_display_now proc far
   push DS 
   push SI
   push AX
   push BX
   push CX
   

   
   MOV BX, LCD_DATA_SEG
   MOV DS, BX
     ;clear display
   MOV BL, LCD_CL_Display
   call far ptr set_LCD_register
   
   mov AL, DS:lines_to_display
   
   and AL, cur_line1
   
   cmp AL, cur_line1
   
   JNE LCD_check_for_line2
   
   ;display line1:
   MOV BL, first_line_LCD_address
   call far ptr set_LCD_register
   
   MOV SI, offset LCD_1st_line_buffer
   MOV CX, LCD_buffer_size
   LCD_display_loop1:
   
   MOV BL,[SI]
   call far ptr write_char_to_LCD
   
   inc SI
   
   ;break
   MOV BL,[SI]
   cmp BL,0H
   
   je LCD_check_for_line2  
   
   loop LCD_display_loop1
   
   LCD_check_for_line2:
   
   mov AL, DS:lines_to_display
   
   and AL, cur_line2
   
   cmp AL, cur_line2
   
   JNE LCD_final_display
     
	;display line 2:
   MOV BL, second_line_LCD_address
   call far ptr set_LCD_register
	
   MOV SI, offset LCD_2nd_line_buffer
   MOV CX, LCD_buffer_size
   
   
   LCD_display_loop2:
   
 
   MOV BL,[SI]
   call far ptr write_char_to_LCD
   
   inc SI
   
   ;break
   MOV BL,[SI]
   cmp BL,0H
   
   je LCD_final_display
   
   loop LCD_display_loop2   
   
   
   
 LCD_final_display:  
   Mov AL, 0
   Mov DS:lines_to_display,AL
   
   pop CX
   pop BX
   pop AX
   pop SI
   pop DS
   ret
LCD_display_now endp






LCD_Routine ENDS

End
